package org.itboys.mobile.util;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.itboys.commons.CommonConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.security.SignatureException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * 手机端接口的安全校验工具类
 * Created by Administrator on 2017/3/3.
 */
public class MobileSignUtils {

    protected static Logger logger = LoggerFactory.getLogger(MobileSignUtils.class);

    /**
     * 签名校验
     * @param param
     * @param sign
     * @return
     */
    public static boolean signCheck( Map<String, Object> param, String sign){
        //除去Map中的空值和签名参数
        Map<String, Object> filtMap = MobileSignUtils.paraFilter(param);
        logger.info("去除空值和sign后，前端传的参数="+ JSON.toJSONString(filtMap));

        //服务端校验签名 统一使用UTF-8编码格式
        boolean signSer = MobileSignUtils.verify(MobileSignUtils.mapToStringOrderByKey(filtMap),
                sign, CommonConstants.DEFAULT_CHARSET);
        logger.info("服务端签名校验结果="+ signSer);

        return signSer;
    }

    /**
     * 除去Map中的空值和签名参数
     * @param sMap 签名参数组
     * @return 去掉空值与签名参数后的新签名参数组
     */
    public static Map<String, Object> paraFilter(Map<String, Object> sMap) {
        Map<String, Object> result = Maps.newHashMapWithExpectedSize(sMap.size());
        if (sMap == null || sMap.size() <= 0) {
            return result;
        }
        for (String key : sMap.keySet()) {
            Object value = sMap.get(key);
            if (value == null || value.equals("") || key.equalsIgnoreCase("sign")) {
                continue;
            }
            result.put(key, value);
        }
        return result;
    }

    /**
     * 把数组所有元素排序，并按照“参数=参数值”的模式用“&”字符拼接成字符串
     * @param params 需要排序并参与字符拼接的参数组
     * @return 拼接后字符串
     */
    public static String mapToStringOrderByKey(Map<String, Object> params) {
        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);

        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            Object value = params.get(key);
            if (i == keys.size() - 1) {//拼接时，不包括最后一个&字符
                sb.append(key + "=" + value);
            } else {
                sb.append(key + "=" + value + "&");
            }
        }
        return sb.toString();
    }

    /**
     * 签名字符串
     * @param text 需要签名的字符串
     * @param input_charset 编码格式
     * @return 签名结果
     */
    public static String sign(String text, String input_charset) {
        return DigestUtils.md5Hex(getContentBytes(text, input_charset));
    }

    /**
     * 签名字符串
     * @param text 需要签名的字符串
     * @param key 密钥
     * @param input_charset 编码格式
     * @return 签名结果
     */
    public static String sign(String text, String key, String input_charset) {
        text = text + key;
        return DigestUtils.md5Hex(getContentBytes(text, input_charset));
    }

    /**
     * 签名字符串，并验证签名是否相同
     * @param text 需要签名的字符串
     * @param sign 签名结果
     * @param key 密钥
     * @param input_charset 编码格式
     * @return 签名结果
     */
    public static boolean verify(String text, String sign, String key, String input_charset) {
        text = text + key;
        String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset));
        if(mysign.equals(sign)) {
            return true;
        }else {
            return false;
        }
    }

    /**
     * 签名字符串，并验证签名是否相同
     * @param text 需要签名的字符串
     * @param sign 签名结果
     * @param input_charset 编码格式
     * @return 签名结果
     */
    public static boolean verify(String text, String sign, String input_charset) {
        String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset));
        logger.info("前端的签名，sign="+sign);
        logger.info("服务端的签名，sign="+mysign);
        if(StringUtils.equals(mysign, sign)) {
            return true;
        }else {
            return false;
        }
    }

    /**
     * @param content
     * @param charset
     * @return
     * @throws SignatureException
     * @throws UnsupportedEncodingException
     */
    private static byte[] getContentBytes(String content, String charset) {
        if (StringUtils.isBlank(charset)) {
            return content.getBytes();
        }
        try {
            return content.getBytes(charset);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
        }
    }

    /*public static void main(String[] args){
        Map<String, Object> param = Maps.newHashMapWithExpectedSize(3);
        param.put("mobile", "1311231313");
        param.put("password", "3123123123");
        param.put("sigin","fff4545");
        param.put("a",11);
        param.put("z",20);
        System.out.println(mapToStringOrderByKey(param));
    }*/
}
